package com.jesse.eclgy.plug.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ReflectUtil;
import com.jesse.eclgy.plug.annotations.TableField;
import com.jesse.eclgy.plug.annotations.TableName;
import com.jesse.eclgy.plug.enums.FieldType;
import com.sun.istack.internal.NotNull;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 反射的 Utils 函数集合
 * 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
 *
 * @Author: jesse
 * @Date: 2023/6/16 9:19
 */
public class ReflectionUtils {


    /**
     * 得到查询的 列 获取对象所有字段 DB名称 和字段列
     *
     * @param clszz
     * @return
     */
    public static Map<String, Field> getFields(@NotNull Class<?> clszz)
    {


        Map<String, Field> fieldMap = new HashMap<>();

        final Field[] fields = ReflectUtil.getFields(clszz);
        for (Field field : fields)
        {
            String name = field.getName();

            if (field.isAnnotationPresent(TableField.class))
            {
                final TableField tableField = field.getAnnotation(TableField.class);
                final List<FieldType> fieldTypes = Arrays.asList(tableField.fieldType());

                if (!fieldTypes.contains(FieldType.ALL) && !fieldTypes.contains(FieldType.QUERY))
                {
                    continue;
                }
                if (StringUtils.isNotBlank(tableField.name()))
                {
                    name = tableField.name();
                }
            }
            fieldMap.putIfAbsent(name, field);
        }
        return fieldMap;
    }
//    public static Map<String, Field> getFields(@NotNull Class<?> clszz)
//    {
//        Map<String, Field> fieldMap = new HashMap<>();
//        final Field[] fields = ReflectUtil.getFields(clszz);
//        for (Field field : fields)
//        {
//            String name = field.getName();
//            if (field.isAnnotationPresent(TableField.class))
//            {
//                final TableField tableField = field.getAnnotation(TableField.class);
//                final List<FieldType> fieldTypes = Arrays.asList(tableField.fieldType());
//                if (fieldTypes.contains(FieldType.ALL) || fieldTypes.contains(FieldType.QUERY))
//                {
//                    if (StringUtils.isNotBlank(tableField.name()))
//                    {
//                        name = tableField.name();
//                    }
//                    fieldMap.putIfAbsent(name, field);
//                }
//            }
//        }
//        return fieldMap;
//    }

    /**
     * 获取 所有字段和值
     *
     * @param obj
     * @param fieldType
     * @return
     */
    public static Map<String, Object> getFieldMap(@NotNull Object obj, @NotNull FieldType fieldType)
    {
        final Class<?> superclass = obj.getClass().getSuperclass();
        final Map<String, Object> superValue = superclass == Object.class ? new LinkedHashMap<>() :
                getFieldValue(superclass, obj, fieldType);
        final Map<String, Object> fieldValue = getFieldValue(obj.getClass(), obj, fieldType);

        superValue.putAll(fieldValue);
        return superValue;
    }


    /**
     * 获取 所有字段和值
     *
     * @param cls
     * @param obj
     * @param fieldType
     * @return
     */
    public static Map<String, Object> getFieldValue(@NotNull Class<?> cls, @NotNull Object obj,
                                                    @NotNull FieldType fieldType)
    {

        Map<String, Object> fieldMap = new LinkedHashMap<>();
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field field : declaredFields)
        {
            String fieldName = field.getName();
            final boolean isAnnPresent = field.isAnnotationPresent(TableField.class);
            String format = null;
            if (isAnnPresent)
            {
                TableField tableField = field.getAnnotation(TableField.class);
                // 不需要主键 列
                if (tableField.isKey() &&
                        (fieldType == FieldType.UPDATE || fieldType == FieldType.DELETE
                                || fieldType == FieldType.INSERT)
                )
                {
                    continue;
                }

                //得到 列属性
                final List<FieldType> fieldTypes = Arrays.asList(tableField.fieldType());

                //字段 是否包含所需
                boolean fla = fieldTypes.contains(FieldType.ALL) || fieldTypes.contains(fieldType);
                if (!fla)
                {
                    continue;
                } else if (StringUtils.isNotBlank(tableField.name()))
                {
                    fieldName = tableField.name();
                }

                format = tableField.format();
            }

            Object fieldValue = ReflectUtil.getFieldValue(obj, field);

            if (fieldType == FieldType.QUERY || null != fieldValue)
            {
                if (fieldValue instanceof Date && StringUtils.isNotBlank(format))
                {
                    final Date date = Convert.toDate(fieldValue);
                    if (date != null)
                    {
                        fieldMap.put(fieldName, DateTime.of(date).toString(format));
                    }
                } else
                {
                    fieldMap.put(fieldName, fieldValue);
                }

            }
        }
        return fieldMap;
    }


    /**
     * 获取主键 名称 和值
     *
     * @param obj
     * @return
     */
    public static Map<String, Object> getKeyField(@NotNull Object obj)
    {
        Map<String, Object> fieldMap = new LinkedHashMap<>();
        final Field keyField = getKeyField(obj.getClass());
        if (keyField != null)
        {
            final String keyName = getKeyName(keyField);
            final Object fieldValue = ReflectUtil.getFieldValue(obj, keyField);
            if (fieldValue != null)
            {
                fieldMap.put(keyName, fieldValue);
            }
        }
        return fieldMap;
    }


    /**
     * 获取属ID名称
     *
     * @param clszz
     * @return
     */
    public static String getKeyName(Class<?> clszz)
    {
        final Field keyField = getKeyField(clszz);
        return getKeyName(keyField);
    }

    /**
     * 根据泛型获取
     *
     * @param clszz
     * @return
     */
    public static String getKeyNameByGenerics(Class<?> clszz)
    {
        final Field keyField = getKeyField(getGenericsClass(clszz));
        return getKeyName(keyField);
    }


    /**
     * 获取属ID名称
     *
     * @param keyField
     * @return
     */
    public static String getKeyName(Field keyField)
    {
        if (keyField == null)
        {
            return null;
        } else
        {
            final TableField annotation = keyField.getAnnotation(TableField.class);
            return StringUtils.isNotBlank(annotation.name()) ? annotation.name() : keyField.getName();
        }
    }


    /**
     * 获取主键列
     *
     * @param clszz
     * @return
     */
    public static Field getKeyField(final Class<?> clszz)
    {
        if (clszz == Object.class)
        {
            return null;
        }

        clszz.getAnnotationsByType(TableField.class);
        AtomicReference<Field> id = new AtomicReference<>();
        Arrays.stream(clszz.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(TableField.class)
                        && field.getAnnotation(TableField.class).isKey())
                .forEach(field -> id.set(field));

        return id.get() == null ? getKeyField(clszz.getSuperclass()) : id.get();

    }

    /**
     * 是否泛型 里面获取
     *
     * @param objClass
     * @return
     */
    public static String getTableName(Class<?> objClass)
    {
        return getTableName(objClass, true);
    }

    /**
     * 根据泛型 得到class获取 表名称
     *
     * @param objClass
     * @return
     */


    public static String getTableName(Class<?> objClass, boolean isType)
    {
        //得到 泛型 的 CLASS
        Class<?> clszz = isType ? getGenericsClass(objClass) : objClass;

        String tableName = "";
        if (clszz.isAnnotationPresent(TableName.class))
        {
            final TableName annotation = clszz.getAnnotation(TableName.class);
            tableName = annotation.value();
        }
        return tableName;
    }

    /**
     * 获取 对象泛型 的class
     *
     * @param clszz
     * @return
     */
    public static Class<?> getGenericsClass(Class<?> clszz)
    {

        // 拿到当前的匿名类的class对象
        Class<?> parameterizedTypeReferenceSubclass = findParameterizedTypeReferenceSubclass(clszz);
        if (parameterizedTypeReferenceSubclass == Object.class || parameterizedTypeReferenceSubclass.getSuperclass() == Object.class)
        {
            parameterizedTypeReferenceSubclass = clszz;
        }

// 再获取匿名类的父类，也就是TypeReference的类型信息
        Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();

        ParameterizedType parameterizedType = (ParameterizedType) type;
        if (parameterizedType.getActualTypeArguments()[0] instanceof Class)
        {
            return (Class<?>) parameterizedType.getActualTypeArguments()[0];
        }

        return parameterizedType.getActualTypeArguments()[0].getClass();
    }


    /**
     * 获取BaseDao的层
     *
     * @param child
     * @return
     */
    public static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child)
    {
        if (child == Object.class)
        {
            return child;
        }

        Class<?> parent = child.getSuperclass();
        return Object.class == parent ? child : findParameterizedTypeReferenceSubclass(parent);

    }


}
